<html>
<head>

<style>
	body {font-family: monospace;}
	form { margin: 0px; padding: 0px; display: inline; }
	#tabs { position: absolute; top: 5px; left: 5px; right: 5px; }
	#tabs > span {cursor: pointer;height: 20px; display: inline-block; padding: 5px;}
	#tabs > .active {background: #eee; }
	#tabs .close:hover { color: red; }
	#body {  position: absolute; top: 35px; bottom: 5px; left: 5px; right: 5px; background: #eee;}
	#body > div { position: absolute; top: 0px; bottom: 0px; left: 0px; width: 70em; padding: 5px; border-right: 2px dashed #ccc; overflow-y: scroll;}
	#console { position: fixed; bottom: 0px; left: 5px; right: 5px; padding: 2px; border: solid 1px green; background: #eee;}
	#console > input, #console > input:focus{background: #eee; width: auto; border: none!important;}
	#console > span, #console > input{ padding: 0px; margin: 0px;}

	#help { position: fixed; top: 35px; right: 5px; color: grey}
	#help tr > td:first-child { text-align: right }

	#marked { background: cyan }
</style>
<script type="text/javascript" src="http://rangy.googlecode.com/svn/trunk/currentrelease/rangy-core.js"></script>
<script type="text/javascript" src="http://rangy.googlecode.com/svn/trunk/currentrelease/rangy-selectionsaverestore.js"></script>
<script type="text/javascript" src="javascript/Base.js"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script>
shortcuts = {
	"modifiers" : {
		"m-x" : { "keyCode":  88, "altKey": true, "display": "Write full command" },
		"c-x" : { "keyCode": 88, "ctrlKey": true, "display": "File operations"},
	}, "shortcuts" : {
		"c-x c-f" : { "keyCode": 70, "ctrlKey": true, "modifier": "c-x", "display": "Find File", 
			"afterPress": function () {				
				$("<form></form>").attr("enctype","multipart/form-data").append(
					$("<input type='file' name='file'></input>").change( function(){ new Buffer( $(this)[0].files[0].name, { formdata: new FormData($(this).parent().get(0)) }) ; $(this).parent().remove() } )
				).insertAfter($("#console")).css({position:"fixed", bottom:0, right:5})
			},
			"afterInput": function(){new Buffer($("#console .input").val()) }},
		"c-x c-c" : { "keyCode": 67, "ctrlKey": true, "modifier": "c-x", "display": "Kill Buffer", "afterPress": function(){Buffers[$("#body > :visible").attr("buffer_id")].kill();}},
		
	}
}

Buffer = Base.extend({
	constructor : function( file , options ) {
		$(":file").parent().remove();
		if (!file) return false;
		this.file = file;
		if (!window["Buffers"]) window["Buffers"] = [];
		window.Buffers.push(this);
		this.use_php_file_loader = true;
		this.show_after_loading = true;
		this.auto_load_mode = true;
		this.do_after_loading = function() { this.show() };
		this.basename = this.file.substr(0,this.file.lastIndexOf("."));
		this.extension = this.file.substr(this.file.lastIndexOf(".")+1,this.file.length);
		if ( options ) this.extend( options );
		if ( this.auto_load_mode ) this.load_mode();
		var t = this;
		$.ajax({
			type : "POST",
			url : t.use_php_file_loader ? "loadfile.php" : t.file , 
			data : t.formdata || (t.use_php_file_loader ? { file : t.file } : {}) , 
			dataType : "text", 
			cache : t.formdata ? false : true ,
			contentType : t.formdata ? false : "application/x-www-form-urlencoded; charset=UTF-8" ,
			processData : t.formdata ? false : true ,
			success : function(data) { 
				t.raw = data;
				if ( t.do_after_loading instanceof Function || typeof t.do_after_loading == "function") { t.do_after_loading() }
			}, error : function () {
				console.log("error loading requested file")
			}
		})
	},
	reload : function ( options ) {
		
	},
	load_mode : function () {
		switch (this.extension.toLowerCase()) {
			case "org" : 
				this.mode = "OrgMode";
				break;
			default : this.mode = "plaintext";
		};
		this.extend( window[this.mode] || {} )
		if ( this.stylesheets ) $("<style></style>").html(this.stylesheets).appendTo($("head"));
	},
	open : function () {
		var t = this;
		if (!t.formatted && t.format) {	t.format() } else { t.formatted = t.raw }
		if (!t.tab || !t.container) {
			$(t.tab, t.container).remove();
			t.tab = $("<span></span>").appendTo("#tabs").click(function(){t.show()}).html(t.file+" ").append($("<span></span>").html("&#10005;").addClass("close").click(function(){t.kill()}));
			t.container = $("<div></div>").addClass("file "+t.mode).hide().attr("contenteditable",true).attr("file", t.file.replace(".","_")).appendTo("#body").html(t.formatted).attr("buffer_id",window.Buffers.indexOf(this));
		}
	},
	show : function () {
		if (!this.container) this.open();
		this.container.siblings().hide().end().show();
		this.tab.siblings().removeClass("active").end().addClass("active");
	},
	kill : function () {
		this.container.siblings().first().show().end().end().remove(); 
		this.tab.siblings().first().addClass("active").end().end().remove();
		delete window.Buffers.indexOf(this);
	}
})
plaintext = {
	format : function () {
		if (!this.raw) return false
		this.formatted = this.raw.replace(/([^>])\n(?!<)+/g,"$1<br>").replace(/\n/g,"");
	}
}
OrgMode = {
	modifiers : {
		"c-c" : { "keyCode": 67, "ctrlKey": true, "display": "org-Mode operations"}
	},
	shortcuts : {
		"c-c c-c" : { "keyCode": 67, "ctrlKey": true, "modifier": "c-c", "display": "Edit Tags", 
			"afterPress": function(){
				$("#console .input").text($(".caret").parent().find(".tags").text());
			}, "afterInput": function(){
				tags = $("#console .input").text().split(":"); var html ="";
				$.each(tags, function(id,tag){ if ( tag != "" ) html+= "<span class='tags "+tag.toLowerCase()+"'>:"+tag+":</span>"; })
				$(".caret").parent().find(".tags").remove().end().append(html);
			}
		}, "c-p" : { keyCode : 80, ctrlKey: true, afterPress: function() { this.move_cursor("up") }
		}, "c-n" : { keyCode : 78, ctrlKey: true, afterPress: function() { this.move_cursor("down") }
		}, "c-b" : { keyCode : 66, ctrlKey: true, afterPress: function() { this.move_cursor("left") }
		}, "c-f" : { keyCode : 70, ctrlKey: true, afterPress: function() { this.move_cursor("right") }
		}, "c-up" : { keyCode : 38, ctrlKey: true, afterPress: function() { this.move_outline("up") }
		}, "c-down" : { keyCode : 40, ctrlKey: true, afterPress: function() { this.move_outline("down") }
		}, "c-left" : { keyCode : 37, ctrlKey: true, afterPress: function() { this.move_outline("left") }
		}, "c-right" : { keyCode : 39, ctrlKey: true, afterPress: function() { this.move_outline("right") }
		}, "tab" : { keyCode : 9, afterPress: function() { this.toggle_outline() }
		}
	}, stylesheets : "	\
		.OrgMode .comment { color: grey; font-size: smaller } \
		.OrgMode .todostates { font-weight: bold } \
		.OrgMode .todostates.todo { color: firebrick; } \
		.OrgMode .todostates.asap { color: red;} \
		.OrgMode .todostates.done { color: green; } \
		.OrgMode .tags { float: right; opacity: 0.5} \
		.OrgMode .tags:hover { opacity: 1} \
		.OrgMode .tags.privat { background: green} \
		.OrgMode .tags.arbeit { background: red} \
		.OrgMode .tags.uni { background: orange} \
		.OrgMode .tags.buch { background: yellow} \
		.OrgMode .drawer { color: purple; font-size: small } \
		.OrgMode .content { margin-left: 10px; margin-right: 20px;} \
		.OrgMode .underline { text-decoration: underline } \
		.OrgMode .strong { font-weight: bold } \
		.OrgMode .strike { text-decoration: line-through } \
		.OrgMode .emphasis { font-style: italic } \
		.OrgMode .code { font-family: monospace; color: grey } \
	",
	format : function () {
		if (!this.raw) return false;
		this.formatted = this.formatOutline( this.raw );
		this.formatted = this.formatOnTheFly( this.formatted );
		this.formatted = this.formatted.replace(/([^>])\n(?!<)+/g,"$1<br>").replace(/\n/g,"");
	},
	open : function () {
		this.base();
		this.switchFormatOnTheFly(true);
		this.addListenersToNodes();
	},
	addListenersToNodes : function() {	
		var t = this;
		this.container.find(".drawer, .outline").dblclick(function(){t.toggle_outline($(this))}).append("<span class='ellipsis'>&hellip;</span>").next().hide();
	},
	formatting_keys : [107, 187,107,106,198,55,16,8,46,61],
	switchFormatOnTheFly : function ( s ) {
		var t = this;
		if (!s) { this.container.off(); return this; } else {
			this.container.on("keyup", function(e){
				var selkeyup = rangy.saveSelection();
				var sel = rangy.getSelection();
				var k = e.keyCode;

				if (t.formatting_keys.indexOf(k) > -1) {
					var n = $(sel.focusNode);
					while ( ! n.is(".file, .content, .outline") ) n = n.parent();
					n.html(t.formatOnTheFly(n.html()));
				}
				rangy.restoreSelection(selkeyup);
			})
		}
	},
	formatOnTheFly : function ( v ) {
		return v.replace(/<(strong|em|u|strike|a)>/gm,"").replace(/<\/(strong|em|u|strike|a)>/gm,"")
		.replace(/(\s|&nbsp;)(\+[^\n+]+?[^\s]\+)(?=[\s.,;:-_?!\"]|&nbsp;)/mg, "$1<span class='strike'>$2</span>") // STRIKETHROUGH
		.replace(/(\s|&nbsp;)(\*[^\n*]+?[^\s]\*)(?=[\s.,;:-_?!\"]|&nbsp;)/mg, "$1<span class='strong'>$2</span>") // STRONG
		.replace(/(\s|&nbsp;)(\=[^\n=<>]+?[^\s]\=)(?=[\s.,;:-_?!\"]|&nbsp;)/mg, "$1<span class='code'>$2</span>")
		.replace(/(\s|&nbsp;)(\/[^\n\/]+?[^\s]\/)(?=[\s.,;:-_?!\"]|&nbsp;)/mg, "$1<span class='emphasis'>$2</span>") // EMPHASIS
		.replace(/(\s|&nbsp;)(_[^\n_]+?[^\s]_)(?=[\s.,;:-_?!\"]|&nbsp;)/mg, "$1<span class='underline'>$2</span>") // UNDERLINE
		.replace(/\[\[(\S+)\]\[(\S+)\]\]/gm, function(s,m1,m2) { return "<a href=\""+( /\.org/g.test(m1) ? "javascript:load('"+m1+"')" : m1 )+"\">"+m2+"</a>"}) // ANCHORS WITH TITLE
		.replace(/\[\[(\S+)\]\]/gm, function(s,m1){return "<a href=\""+( /\.org/g.test(m1) ? "javascript:load('"+m1+"')" : m1 )+"\">"+m1+"</a>"}) // ANCHORS WITHOUT TITLE
	},
	formatOutline : function ( v ) {
		return (v+"\n\n* <!--end--/>")// ADD A STAR TO END OF FILE AND A MARK TO FIND IT LATER ON
		.replace(/([a-zA-Z]):([a-zA-Z])/g, "$1: :$2") //prepare for tags
		.replace(/.(:)([a-zA-Z]+?)(:)(?!<)/g, function(s,m1,m2,m3) { return "<span class='tags "+m2.toLowerCase()+"'>"+m1+m2+m3+"</span>" }) // TAGS 
		.replace(/^(\*{4}\s.+)([\s\S]*?)(?=^\*{1,4}\s)/mg, "<div class='outline h4'>\n$1\n</div><div class='content'>\n$2\n</div>\n") // OUTLINES
		.replace(/^(\*{3}\s.+)([\s\S]*?)(?=^\*{1,3}\s)/mg, "<div class='outline h3'>\n$1\n</div><div class='content'>\n$2\n</div>\n")
		.replace(/^(\*{2}\s.+)([\s\S]*?)(?=^\*{1,2}\s)/mg, "<div class='outline h2'>\n$1\n</div><div class='content'>\n$2\n</div>\n")
		.replace(/^(\*{1}\s.+)([\s\S]*?)(?=^\*{1}\s)/mg, "<div class='outline h1'>\n$1\n</div><div class='content'>\n$2\n</div>\n")
		.replace(/^(\*{1,4}\s)([A-Z]{1,10})(?=\s)/mg , function(s,m1,m2) { return m1+"<span class='todostates "+m2.toLowerCase()+"'>"+m2+"</span>"}) // TODO STATES
		.replace(/\*\s<!--end--\/>/,"") // END OF FILE
		.replace(/(#\+.+)/g,"<div class='comment'>\n$1\n</div>") // COMMENTS
		.replace(/^(:[A-Z]+:)([\s\S]*?:END:)/gm, "<div class='drawer'>\n$1\</div><div>\n$2\</div>")  // DRAWERS
	},
	toggle_outline : function(t) {
		if (!t) { 
			var t = $(rangy.getSelection().focusNode);
			while( ! t.is(".outline, .content, .file") ) t = t.parent(); t = t.is(".file") ? t.children(".outline") : ( t.is(".content") ? t.prev() : t );
		}
		if ( t.next().is(":visible") ) {
			if ( ! this.toggle_outline(t.next().children(".outline")) ) { t.find(".ellipsis").toggle().end().next().toggle(); return false; }
		} else if ( t.length > 0 ){
			t.find(".ellipsis").toggle().end().next().toggle(); return true;
		} else { return false }
	},
	move_outline : function (d, t) {
		var sel = rangy.saveSelection(); if (!t) var t = $(rangy.getSelection().focusNode);
		switch (d) {
			case "right" : 
				var p; while ( ! t.is(".outline, .content")) t=t.parent(); t = t.is(".outline") ? t.add(t.next()) : t.add(t.prev());
				if ((p = t.prev(".content")).length < 1 && t.prev(".outline").length > 0 ) p = $("<div class='content'></div>").insertAfter(t.prev(".outline"))
				if ( p.length > 0 )t.appendTo(p.show()).filter(".outline").prepend("*").attr("class", t.filter(".outline").attr("class").replace(/h(\d)/g, function(s,m){return "h"+(parseInt(m)+1)}));
			break;
			case "left" : 
				while ( ! t.is(".outline, .content")) t=t.parent(); t = t.is(".outline") ? t.add(t.next()) : t.add(t.prev());	
				t.insertAfter(t.parent()).filter(".outline").attr("class", t.filter(".outline").attr("class").replace(/h(\d)/g, function(s,m){return "h"+(parseInt(m)-1)})).html(t.html().replace(/\*(\s.)/,"$1"));
			break;
			case "up" : 
				while ( ! t.is(".outline, .content")) t=t.parent(); t = t.is(".outline") ? t.add(t.next()) : t.add(t.prev());	
				t.insertBefore(t.first().prevAll(".outline").first())
			break;
			case "down" : 
				while ( ! t.is(".outline, .content")) t=t.parent(); t = t.is(".outline") ? t.add(t.next()) : t.add(t.prev());
				t.insertAfter(t.last().nextAll(".content").first())
			break;
		}
		$("div:empty").remove();
		rangy.restoreSelection(sel);
	}
}
$.fn.filterNfind = function(selector) {
    return this.filter(selector).add(this.find(selector));
};
$.fn.outerHtml = function() { return $(this).clone().wrapAll("<p></p>").parent().html() }
$.fn.nextAllUntil = function(s){
	var t = $(this), p = t.parent(), a = p.contents(), s = $(s), c = [], m = false, i;
	for (i in a) {
		if ( a.hasOwnProperty(i)) {
			if ( a.eq(i).outerHtml() == t.outerHtml() ) m = true;
			if ( a.eq(i).outerHtml() == s.outerHtml() ) m = false;
			if ( m == true ) c.push(a.eq(i))
		}
	}
	return $(c)
}
$.fn.setCursor = function(pos) {
	setCursor($(this).get(0),pos||0); return $(this);
}
function fireKey(el, key){
    if(document.createEventObject) {
        var eventObj = document.createEventObject();
        eventObj.keyCode = key;
		el.fireEvent("onkeydown", eventObj);   
    }else if(document.createEvent) {
        var eventObj = document.createEvent("Events");
        eventObj.initEvent("keypress", true, true);
        eventObj.which = key;
		eventObj.charCode = key;
		eventObj.keyCode = key;
        el.dispatchEvent(eventObj);
    }
	console.log(el);console.log(key);
} 
function insertTextAtCursor(text) {
	var sel, range, html;
	if (window.getSelection) {
		sel = window.getSelection();
		if (sel.getRangeAt && sel.rangeCount) {
			range = sel.getRangeAt(0);
			range.deleteContents();
			range.insertNode( typeof(text) == "string" ? document.createTextNode( text ) : text );
		}
	} else if (document.selection && document.selection.createRange) {
		document.selection.createRange().text = text;
	}
}
function setCursor(node,pos){
	var node = (typeof node == "string" || node instanceof String) ? $(node).get(0) : node;
	console.log(node);
	if(!node){
		return false;
	}else if(node.createTextRange){
		var textRange = node.createTextRange();
		textRange.collapse(true);
		textRange.moveEnd(pos);
		textRange.moveStart(pos);
		textRange.select();
		return true;
	}else if(node.setSelectionRange){
		node.setSelectionRange(pos,pos);
		return true;
	}
	return false;
}
function edit_tags(tags){	
	tags = tags.split(":"); var html ="";
	$.each(tags, function(id,tag){ if ( tag != "" ) html+= "<span class='tags "+tag.toLowerCase()+"'>:"+tag+":</span>"; })
	$(".caret").parent().find(".tags").remove().end().append(html);
}
$(function(){

	$("#help").append(function(){
		var c=[], h="";
		$.each(shortcuts.shortcuts, function(id,key){
			h = "<tr><td>"+id+"</td><td>: "+key.display+"</td><td>"+(key.afterInput ? "input needed" : "without input")+"</td></tr>";
			c.push(h);
		})		
		return c
	})

	$("body").keydown(function(e){
		var t = $("#console .input"), a = true, el = $("#body > :visible"), buffer, s = ( el.length > 0 ) ? ( buffer = Buffers[el.attr("buffer_id")]).shortcuts || {} : {}, m = ( el.length > 0 ) ? Buffers[el.attr("buffer_id")].modifiers || {} : {};		
		$.each(m, function(id, h) {
			if (h.keyCode == e.keyCode && ( h.shiftKey || false ) == e.shiftKey && ( h.altKey || false ) == e.altKey && ( h.ctrlKey || false ) == e.ctrlKey && t.attr("modifier") == "" ) {
				e.stopPropagation(); e.preventDefault();
				$("#console").show().children(".display").html(id + " : " + h.display+": ").next().attr("modifier",id).focus();
				a = false;
			}
		})
		$.each(shortcuts.modifiers, function(id, h) {
			if (h.keyCode == e.keyCode && ( h.shiftKey || false ) == e.shiftKey && ( h.altKey || false ) == e.altKey && ( h.ctrlKey || false ) == e.ctrlKey && t.attr("modifier") == "" && a == true) {
				e.stopPropagation(); e.preventDefault();
				$("#console").show().children(".display").html(id + " : " + h.display+": ").next().attr("modifier",id).focus();
				a = false;
			}
		})
		$.each(s, function(id, h){
			if (h.keyCode == e.keyCode && ( h.shiftKey || false ) == e.shiftKey && ( h.altKey || false ) == e.altKey && ( h.ctrlKey || false ) == e.ctrlKey && ( t.attr("modifier") ? (t.attr("modifier") == h.modifier) : true ) && a == true) {
				console.log(e);
				e.stopPropagation(); e.preventDefault();
				if ( h.display ) $("#console").show().children(".display").html(id + " : " + h.display+": ").next().focus()
				if ( h.afterPress ) if (buffer) {h.afterPress.apply(buffer) } else {h.afterPress()};
				if ( h.afterInput ) 
					$("#console .input").off("keypress").on("keypress", function (e) { 
						if ( e.keyCode == 13 ) { e.stopPropagation(); e.preventDefault(); if (buffer) { h.afterInput.apply(buffer) } else { h.afterInput() }; t.blur()}
					})
				a = false;
			}
		})
		$.each(shortcuts.shortcuts, function(id, h){
			if (h.keyCode == e.keyCode && ( h.shiftKey || false ) == e.shiftKey && ( h.altKey || false ) == e.altKey && ( h.ctrlKey || false ) == e.ctrlKey && ( t.attr("modifier") ? (t.attr("modifier") == h.modifier) : true ) && a == true) {
				e.stopPropagation(); e.preventDefault();
				if ( h.display ) $("#console").show().children(".display").html(id + " : " + h.display+": ").next().focus()
				if ( h.afterPress ) if (buffer) {h.afterPress.apply(buffer) } else {h.afterPress()};
				if ( h.afterInput ) 
					$("#console .input").off("keypress").on("keypress", function (e) { 
						if ( e.keyCode == 13 ) { e.stopPropagation(); e.preventDefault(); if (buffer) { h.afterInput.apply(buffer) } else { h.afterInput() }; t.blur()}
					})
			}
		})
	})
	
	$("#console")
	.hide()
	.children(".input")
	.blur(function() {$(this).attr("modifier","").val("").parent().hide().off("keypress")})
})
</script>
</head>
<body>
<div id="tabs"></div>
<div id="body"></div>
<table id="help">
<tr><td colspan=3>m = &lt;ALT&gt;, c = &lt;CTRL&gt; s = &lt;SHIFT&gt; </td></tr>
</table>
</body>
<form id="console">&gt;&nbsp;<span class="display"></span><input class="input" type="text" modifier=""></input></form>